#ifndef TRIGGER_H
#define TRIGGER_H

#include <iostream>
#include <vector>

#include "../../util/CHandle.h"

class TriggerBooleanExpression;
class TriggerExecutionScope;

template <typename RETURN_TYPE>
class JassFunction;
template <typename RETURN_TYPE>
class CodeJassValue;

static int STUPID_STATIC_TRIGGER_COUNT_DELETE_THIS_LATER = 452354453;

template <typename RETURN_TYPE>
class Trigger : CHandle {
private:
    int handleId;
    std::vector<TriggerBooleanExpression> conditions;
    std::vector<JassFunction<RETURN_TYPE>> actions;
    int evalCount;
    int execCount;
    bool enabled = true;
    bool waitOnSleeps = true;
    // used for eval
    TriggerExecutionScope triggerExecutionScope;

public:
    Trigger() : handleId(STUPID_STATIC_TRIGGER_COUNT_DELETE_THIS_LATER++), evalCount(0), execCount(0), triggerExecutionScope(this){}

    int addAction(JassFunction<RETURN_TYPE> function) {
        int index = actions.size();
        actions.add(function);
        return index;
    }

    int addAction(CodeJassValue<RETURN_TYPE> function) {
        actions.push_back(new JassThreadActionFunc(function));
        return actions.size() - 1;
    }

    //int addCondition(TriggerBooleanExpression* boolexpr) {
    //    conditions.push_back(boolexpr);
    //    return conditions.size() - 1;
    //}

    //void removeCondition(TriggerBooleanExpression* boolexpr) {
    //    for (auto it = conditions.begin(); it != conditions.end(); ++it) {
    //        if (*it == boolexpr) {
    //            conditions.erase(it);
    //            break;
    //        }
    //    }
    //}

    void removeConditionAtIndex(int index) {
        conditions.erase(conditions.begin() + index);
    }

    void clearConditions() {
        conditions.clear();
    }

    int getEvalCount() const { return evalCount; }

    int getExecCount() const { return execCount; }

    /*bool evaluate(GlobalScope* globalScope, TriggerExecutionScope* triggerScope) {
        for (auto condition : conditions) {
            if (!condition->evaluate(globalScope, triggerScope)) {
                return false;
            }
        }
        return true;
    }

    void execute(GlobalScope* globalScope, TriggerExecutionScope* triggerScope) {
        if (!enabled)
            return;

        for (auto action : actions) {
            try {
                action->call(Collections(), globalScope, triggerScope);
            }
            catch (std::exception& e) {
                throw std::runtime_error("Exception during Trigger action execute");
            }
        }

        execCount++;
    }*/

    bool isEnabled() const { return enabled; }

    void setEnabled(bool enabled_) { enabled = enabled_; }

    void destroy() {} // empty function

    void reset() {
        actions.clear();
        conditions.clear();
        evalCount = 0;
        execCount = 0;
        enabled = true;
        waitOnSleeps = true;
    }

    void setWaitOnSleeps(bool waitOnSleeps_) { waitOnSleeps = waitOnSleeps_; }

    bool isWaitOnSleeps() const { return waitOnSleeps; }
};

#endif // TRIGGER_H
